#include "module_buffer.h"
#include <string.h>	/* memset */
#include <stddef.h>	/* NULL */

/* 一个模块缓存和一个系统缓存的对应 */
typedef struct _mod_buf_pair {
	queue_t queue;	/* 一个系统缓存的队列节点 */
	mod_buf_t mbuf;	/* 一个模块缓存 */
} mod_buf_pair_t;

static const mod_buf_t mbuf_null = {NULL, 0};
/* 所有的系统缓存都和模块缓存进行绑定 */
static mod_buf_pair_t all_mbuf[QBUF_MAX_COUNT];

/* 私有函数 */
/**
 * \brief	将一个系统缓存从它原来的队列中剥离，加入到模块相关的队列中进行预绑定
 * \param	qentry:	模块中的队列
 * \param	qbuf: 原来的系统缓存
 */
static mod_buf_pair_t *modbuf_find_pair(queue_entry_t *qentry, qbuf_t *qbuf, int gid)
{
	queue_lock_t lock;
	mod_buf_pair_t *mbuf_pair = NULL;
	mod_buf_t *mbuf = NULL;

	if (!qbuf)
		return NULL;

	queue_lock(lock);

	for (int i = 0; i < QBUF_MAX_COUNT; i++) {
		mbuf_pair = &all_mbuf[i];
		mbuf = &(mbuf_pair->mbuf);
		if (!mbuf->qbuf) {
			break;	/* 找到一个没有和系统缓存绑定的本模块缓存变量 */
		}
		mbuf_pair = NULL;
	}

	if (mbuf_pair) {
		mbuf->qbuf = qbuf;
		mbuf->group_id = gid;
		queue_init(&mbuf_pair->queue);
		mbuf_pair->queue.queue_entry = qentry;	/* 重新和本模块队列预绑定 */
	}

	queue_unlock(lock);

	return mbuf_pair;
}

/**
 * \brief	预释放模块缓存
 */
static qbuf_t *modbuf_pre_free(mod_buf_pair_t *mbuf_pair)
{
	queue_lock_t lock;
	qbuf_t *qbuf = NULL;

	if (mbuf_pair == NULL)
		return NULL;

	queue_lock(lock);

	qbuf = mbuf_pair->mbuf.qbuf;
	mbuf_pair->mbuf.qbuf = NULL;

	queue_unlock(lock);

	return qbuf;
}

/* 接口函数 */
/**
 * \brief	初始化所有和模块绑定的缓存变量
 */
void modbuf_pre_init(void)
{
	memset(all_mbuf, 0, sizeof(all_mbuf));
}

/**
 * \brief	初始化本模块的缓存队列
 * \param	modc:	模块上下文结构体指针
 */
void modbuf_init(mod_context_t *modc)
{
	if (!modc)
		return;
	
	queue_entry_init(&modc->qentry);
}

/**
 * \brief	清除该模块中从指定缓存组来的缓存
 * \param	gid:	要清除的缓存组名
 */
void modbuf_destroy_by_group(mod_context_t *modc, int gid)
{
	qbuf_t *qbuf = NULL;

	if (!modc || gid < MOD_GROUP_SYS || gid >= MOD_GROUP_MAX)
		return;

	do {
		qbuf = modbuf_pop(modc, gid);
		if (qbuf) {
			qbuf_free(qbuf);	/* 将该缓存放回到系统空闲缓存队列 */
		}
	} while (qbuf != NULL);
}

/**
 * \brief	清除指定模块中所有缓存组的缓存
 */
void modbuf_destroy(mod_context_t *modc)
{
	if (!modc)
		return;

	for (int i = 0; i < MOD_GROUP_MAX; i++) {
		modbuf_destroy_by_group(modc, i);
	}

	queue_entry_init(&modc->qentry);
}

/**
 * \brief	向指定模块的指定缓存组发送一个缓存
 * \note	发送缓存前需向系统缓存申请一个，作为传入的qbuf参数
 */
mod_buf_t *modbuf_push(mod_context_t *modc, int gid, qbuf_t *qbuf)
{
	mod_buf_pair_t *mbuf_pair;
	mod_buf_t *mbuf;

	if (!modc || !qbuf || gid < MOD_GROUP_SYS || gid >= MOD_GROUP_MAX)
		return NULL;

	/* 将一个系统缓存从它原来的队列中剥离，加入到模块相关的队列中进行预绑定 */
	mbuf_pair = modbuf_find_pair(&modc->qentry, qbuf, gid);
	if (!mbuf_pair)
		return NULL;

	mbuf = &mbuf_pair->mbuf;

	/* 如果是不进入目标模块的队列，让目标模块立即处理 */
	if (modc->bufchange)
		modc->bufchange(&mbuf);

	if (!mbuf->qbuf) {
		/* 如果目标模块自行截留了缓存，它稍后自行决断如何释放，则此处不释放 */
		modbuf_pre_free(mbuf_pair);	/* 预释放模块缓存 */
		return (mod_buf_t *)(&mbuf_null);
	}

	/* 将缓存加入到目标模块的指定队列组中 */
	queue_put(&modc->qentry, &mbuf_pair->queue, gid);

	return mbuf;
}

/**
 * \brief	从指定模块的指定缓存组弹出一个缓存
 */
qbuf_t *modbuf_pop(mod_context_t *modc, int gid)
{
	qbuf_t *qbuf = NULL;
	mod_buf_pair_t *mbuf_pair;

	if (!modc || gid < MOD_GROUP_SYS || gid >= MOD_GROUP_MAX)
		return NULL;

	/* queue_get返回的首地址是一样的，这里省去了调用container_of的过程 */
	mbuf_pair = (mod_buf_pair_t *)queue_get(&modc->qentry, gid);
	if (mbuf_pair)
		qbuf = modbuf_pre_free(mbuf_pair);

	return qbuf;
}

/**
 * \brief	查询指定模块的指定缓存组内已缓存的个数
 */
int modbuf_count(mod_context_t *modc, int gid)
{
	if (!modc || gid < MOD_GROUP_SYS || gid >= MOD_GROUP_MAX)
		return 0;

	return queue_count(&modc->qentry, gid);
}
